package cooperated

import (
	"fmt"

	"gddgame.cc/galaxy/common/feature/orbit/chess_protocol"
	"gddgame.cc/galaxy/common/namespaces/cooperate"
	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
	"gddgame.cc/galaxy/project/breeder/breeder/center"
	"gddgame.cc/galaxy/project/breeder/breeder/model"
	"gddgame.cc/galaxy/utils"
)

type TypeMap struct {
	*TypeManager
	cooperate.MapBase

	Map            *ExtendMap
	regionIndexMap map[string]int

	regionIdentity []int
}

func NewStrategyMap(st *TypeManager) *TypeMap {
	sm := &TypeMap{
		TypeManager: st,
	}

	return sm
}

func (logic *TypeMap) BindMapBase(proxy cooperate.MapBase) {
	logic.MapBase = proxy
}

func (logic *TypeMap) ParseMap(data []byte) {
	extendMap := NewExtendMap()
	if err := extendMap.Parse(data); err != nil {
		fmt.Println(err)
		return
	}
	logic.Map = extendMap
	logic.regionIndexMap = map[string]int{}
	for index, r := range *extendMap.Regions {
		p := utils.ToString(r)
		logic.regionIndexMap[p] = index
	}
	logic.regionIdentity = make([]int, len(logic.regionIndexMap))
}

func (logic *TypeMap) TransformLoad(t structure.PublicDataType, instance cooperate.PropsInstance, message *chess_protocol.Message) (string, interface{}) {
	var location string

	data := &chess_protocol.SingleData{
		DataType: byte(t),
		Data: &chess_protocol.Data{
			Range: logic.TypeManager.DataRange(instance),
		},
	}

	if message != nil {
		data.Data.Message = message.Copy()
	}

	fd := logic.GetFieldsDefine(t)
	for _, pt := range fd.Types {
		value := instance.Receive(pt)
		if value == nil {
			continue
		}
		value.ChessProp(data.Data)
		switch pt {
		case IdPropType:
			idProp := value.(*IdProp)
			data.Id = idProp.Id
		case NodePropType:
			nodeProp := value.(*NodeProp)
			data.Id = nodeProp.Id
		case MapPropType:
			mapProp := value.(*MapProp)

			//fmt.Println("load", logic.GetMapNoId(), instance.Data(), mapProp.Position)
			if mapProp.Position != nil && len(mapProp.Position) > 0 {
				location = logic.Location(mapProp.Position)
			}
			//if t == BuildType {
			//	//fmt.Println("load", logic.mapNoId, instance.BaseData(), location)
			//	logic.buildIdMap.Store(utils.ToString(mapProp.Position), utils.ToInt(instance.GetId()))
			//}
		}
	}
	for _, be := range fd.BeDepends {
		if be.DependIsPosition {
			if int(t) >= len(data.Data.ListNode) {
				data.Data.ListNode = append(data.Data.ListNode, make([][][]byte, int(t)-len(data.Data.ListNode)+1)...)
			}
			list := instance.ListNode(be)
			data.Data.ListNode[t] = make([][]byte, 0, len(list))
			for _, item := range list {
				if item.MapNoId != logic.GetMapNoId() {
					continue
				}
				data.Data.ListNode[t] = append(data.Data.ListNode[t], item.Position)
			}
		} else if be.DependIsNo {
			if int(t) >= len(data.Data.ListId) {
				data.Data.ListNo = append(data.Data.ListNo, make([][]int, int(t)-len(data.Data.ListNo)+1)...)
			}
			data.Data.ListNo[t] = instance.ListNo(be)
		} else if be.DependIsId {
			if int(t) >= len(data.Data.ListId) {
				data.Data.ListId = append(data.Data.ListId, make([][]string, int(t)-len(data.Data.ListId)+1)...)
			}
			data.Data.ListId[t] = instance.ListId(be)
		}
	}
	//fmt.Println("load", data.DataType, data.Id)
	return location, data
}

func (logic *TypeMap) OnPreLoadMap() {

}

func (logic *TypeMap) OnInitMap() {
	updateData := cooperate.OperateContent{
		MapNoId:  logic.GetMapNoId(),
		Target:   logic.GetMapTarget(),
		Operates: []cooperate.OperateData{},
	}
	buildFd := logic.GetFieldsDefine(BuildType)
	for _, build := range *logic.Map.Builds {
		result := structure.NewBaseData(BuildType, build.Position)
		instance := cooperate.NewPropInstance(logic, buildFd, result, map[string]interface{}{
			// 各个依赖项
			Key:   build.Key,
			Level: 1,
		})
		owner := cooperate.NewAbilityOwner()
		effect := owner.Generate(logic, instance, logic)
		//logic.buildPositionsMap[utils.ToString(build.Position)] = buildId
		//fmt.Println("build", buildId, index, region.IsBase, region.IsTeleport)

		id := logic.Center.TargetIdMap[BuildType][build.Key]
		buildInfo := logic.Center.BuildMap[id]
		//positions := logic.RangeDistance(build.Position, buildInfo.FixRange-1)
		//for _, position := range positions {
		//	logic.buildPositionsMap[utils.ToString(position)] = buildId
		//}
		create := &CreateTask{
			DataType: BuildType,
			Id:       build.Position,
			Position: build.Position,
			Key:      build.Key,
			Identity: 0,
			Ability: &Ability{
				Level:         1,
				DirectAbility: effect.GetIds(model.DirectAbilityDefine),
				BuffAbility:   effect.GetIds(model.BuffAbilityDefine),
				AttrAbility:   effect.GetSlice(model.AttrAbilityDefine),
			},
			Name: buildInfo.Name,
		}
		taskBuilder := logic.TaskBuilder()
		taskBuilder.BindMapNoId(logic.GetMapNoId()).One(CreateTaskEvent, create).Task(0, nil)
	}
	for _, node := range *logic.Map.Resources {
		if node.Key == "" {
			continue
		}
		nodeId := logic.Center.TargetIdMap[NodeType][node.Key]
		nodeInfo := logic.Center.NodeMap[nodeId]
		update := &CreateTask{
			DataType: NodeType,
			Id:       node.Position,
			Position: node.Position,
			Key:      node.Key,
			Identity: 0,
		}
		if nodeInfo.OnlyPath {
			update.DataType = PathNodeType
		}

		taskBuilder := logic.TaskBuilder()
		taskBuilder.BindMapNoId(logic.GetMapNoId()).One(CreateTaskEvent, update).Task(0, nil)
	}
	for _, region := range *logic.Map.Regions {
		updateData.Operates = append(updateData.Operates, cooperate.NewOperateData(cooperate.CreateOperate, &cooperate.CreateOperateData{
			Data:     *structure.NewBaseData(RegionType, region),
			Position: region,
			InfoKey:  []string{Identity},
			Infos:    []interface{}{0},
			Dependents: []*cooperate.DependentItem{{
				Key:    cooperate.ManageDataType,
				Depend: structure.NewBaseData(cooperate.ManageType, RegionType),
			}},
		}))
	}
	if len(updateData.Operates) > 0 {
		logic.PushOperate(updateData, 0)
	}
}

func (logic *TypeMap) OnUpdateMap() {

}

func (logic *TypeMap) OnStartMap() {
}

func (logic *TypeMap) OnCreateHandle(data *cooperate.CreateOperateData) {
	if data.Dependents == nil {
		data.Dependents = make([]*cooperate.DependentItem, 0, 1)
	}
	// 绑定map关系
	//fmt.Println("createhandle", logic.GetMapNoId(), data.Data, data.Position, data.Dependents)
	data.Dependents = append(data.Dependents, &cooperate.DependentItem{
		Key:    structure.MapDataType,
		Depend: structure.NewBaseData(structure.MapType, logic.GetMapNoId()),
	})
	// 如果是部队，绑定infixed
	// 建筑内，直接忽略
	if data.Data.DataType == UnitType {
		if data.Position == nil || len(data.Position) == 0 {
			data.InfoKey = append(data.InfoKey, Ignore)
			data.Infos = append(data.Infos, true)
		} else {
			lastRegion := data.Position
			//p := utils.ToString(lastRegion)
			build := logic.GetDetailCache(logic, structure.NewBaseData(BuildType, lastRegion))
			//buildId, ok := logic.buildIdMap.Load(p)
			//fmt.Println("create", lastRegion, build)
			if build != nil {
				data.InfoKey = append(data.InfoKey, Ignore)
				data.Infos = append(data.Infos, true)
				data.InfoKey = append(data.InfoKey, LastRegion)
				data.Infos = append(data.Infos, lastRegion)
				// 添加建筑依赖
				data.Dependents = append(data.Dependents, &cooperate.DependentItem{
					Key:    BuildDataType,
					Depend: build.Data(),
				})
			}
		}
		//fmt.Println("create", data.Data, data.InfoKey, data.Infos, data.Dependents)
	}
	i := -1
	for index, key := range data.InfoKey {
		if key == Key {
			i = index
			break
		}
	}
	if i >= 0 {
		key := utils.ToString(data.Infos[i])
		id := logic.Center.TargetIdMap[data.Data.DataType][key]
		//fmt.Println("source", dataType, key, source, define)
		switch data.Data.DataType {
		case NodeType:
			data.InfoKey = append(data.InfoKey, cooperate.Range)
			node := logic.Center.NodeMap[id]
			data.Infos = append(data.Infos, node.Range)
		case BuildType:
			data.InfoKey = append(data.InfoKey, cooperate.Range)
			build := logic.Center.BuildMap[id]
			data.Infos = append(data.Infos, build.Range)
		case UnitType:
			data.InfoKey = append(data.InfoKey, cooperate.Range)
			unit := logic.Center.UnitMap[id]
			data.Infos = append(data.Infos, unit.Range)
		case ItemType:
			data.InfoKey = append(data.InfoKey, cooperate.Range)
			item := logic.Center.ItemMap[id]
			data.Infos = append(data.Infos, item.Range)
		}
	}
}
func (logic *TypeMap) OnCreateBefore(from cooperate.PropsInstance, instance cooperate.PropsInstance) {
	logic.Center.TriggerStat(center.CreateTriggerEvent, logic, from, instance, 0)
}
func (logic *TypeMap) OnCreateAfter(instance cooperate.PropsInstance, current bool) {
	switch instance.GetDataType() {
	case UnitType:
		if current {
			lastRegion := instance.ToBytes(LastRegion)
			//fmt.Println("unit lastregion", lastRegion)
			if lastRegion != nil && len(lastRegion) > 0 {
				return
			}
			position := instance.ToBytes(Position)
			identity := instance.ToInt(Identity)
			// 直接设定占位，可能立即被下一个替换，但不影响，至少该节点可被攻击
			//fmt.Println("unit set block")
			logic.setBlock(instance, nil, position, nil, logic.CurrentTime(), 0, identity, NormalTargetVisible)
			//abilityProp := ReceiveAbilityProp(instance)
			//defendDistance, _ := abilityProp.GetAttr(logic.DefendDistance)
			//fmt.Println("unit defend", position, defendDistance)
			//if defendDistance > 0 {
			//	fmt.Println("unit defend", position)
			//	positions := logic.RangeDistance(position, defendDistance-1)
			//	logic.OnListen(instance, identity, &ListenLogic{
			//		Nodes:  positions,
			//		Switch: true,
			//		Events: []byte{ListenSystemEvent},
			//	}, logic.CurrentTime())
			//}
		}
	case BuildType:
		//fmt.Println("position", instance.BaseData(), pp, abilityProp)
		if current {
			p := instance.ToBytes(Position)
			key := instance.ToString(Key)
			buildId := logic.Center.TargetIdMap[BuildType][key]
			build := logic.Center.BuildMap[buildId]
			level := instance.ToInt(Level)
			buildLevel := build.Levels[level]
			t := instance.ToByte(Type)
			selfIdentity := instance.ToInt(Identity)
			pp := instance.ToBytesSlice(Positions)
			pp = append(pp, p)
			abilityProp := ReceiveAbilityProp(instance)
			logic.UpdateFixed(pp, selfIdentity, t, abilityProp.View, instance.GetItem(), logic.CurrentTime())
			if buildLevel.DefendRange > 0 {
				positions := logic.RangeDistance(p, int(buildLevel.DefendRange-1))
				logic.OnListen(instance, selfIdentity, &ListenLogic{
					Identity: EnemyTargetIdentity,
					Nodes:    positions,
					Switch:   true,
					Events:   []byte{ListenSystemEvent},
				}, logic.CurrentTime())
			}
		}
	case ItemType:
		if current {
			key := instance.ToString(Key)
			itemId := logic.Center.TargetIdMap[ItemType][key]
			item := logic.Center.ItemMap[itemId]
			fmt.Println("item after", instance.Data(), key, itemId, item)
			selfIdentity := instance.ToInt(Identity)
			if item.DefendRange > 0 {
				p := instance.ToBytes(Position)
				positions := logic.RangeDistance(p, int(item.DefendRange-1))
				logic.OnListen(instance.Data(), selfIdentity, &ListenLogic{
					Nodes:  positions,
					Switch: true,
					Events: []byte{ListenSystemEvent},
				}, logic.CurrentTime())
			}
			//abilityProp := ReceiveAbilityProp(instance)
			////fmt.Println("position", info.Target, pp, utils.ToString(result[Key]))
			//logic.UpdateFixed(pp, selfIdentity, t, abilityProp.View, instance.GetItem(), logic.CurrentTime())
		}
	}
}

func (logic *TypeMap) OnUpdateData(instance cooperate.PropsInstance, current bool) {
	switch instance.GetDataType() {
	case NodeType:
		node := instance.(*Node)
		p := utils.ToString(node.Position)
		if index, ok := logic.regionIndexMap[p]; ok {
			logic.regionIdentity[index] = node.Identity
		}
	case BuildType:
	}

}

func (logic *TypeMap) OnResetBefore(from cooperate.PropsInstance, instance cooperate.PropsInstance) {
	var abilityProp *AbilityProp
	abilityProp = ReceiveAbilityProp(instance)
	if abilityProp != nil {
		// 300秒，5分钟
		instance.ClearTimeSorted(logic, BuffAbilityExtend, abilityProp.BuffInfoSlice, abilityProp.lastClearBuffSecond, 300)
	}
}

func (logic *TypeMap) OnResetAfter(instance cooperate.PropsInstance, current bool) {
	switch instance.GetDataType() {
	case NodeType:
		if current {
			p := instance.ToBytes(Position)
			t := instance.ToByte(Type)
			selfIdentity := instance.ToInt(Identity)
			logic.UpdateNode(p, selfIdentity, t)
		}
	case BuildType:
		if current {
			p := instance.ToBytes(Position)
			key := instance.ToString(Key)
			buildId := logic.Center.TargetIdMap[BuildType][key]
			build := logic.Center.BuildMap[buildId]
			level := instance.ToInt(Level)
			buildLevel := build.Levels[level]
			t := instance.ToByte(Type)
			selfIdentity := instance.ToInt(Identity)
			pp := instance.ToBytesSlice(Positions)
			pp = append(pp, p)
			abilityProp := ReceiveAbilityProp(instance)
			logic.UpdateFixed(pp, selfIdentity, t, abilityProp.View, instance.GetItem(), logic.CurrentTime())
			if buildLevel.DefendRange > 0 {
				positions := logic.RangeDistance(p, int(buildLevel.DefendRange-1))
				logic.OnListen(instance, selfIdentity, &ListenLogic{
					Identity: EnemyTargetIdentity,
					Nodes:    positions,
					Switch:   true,
					Events:   []byte{ListenSystemEvent},
				}, logic.CurrentTime())
			}
		}
	case ItemType:
		if current {
			key := instance.ToString(Key)
			itemId := logic.Center.TargetIdMap[ItemType][key]
			item := logic.Center.ItemMap[itemId]

			selfIdentity := instance.ToInt(Identity)
			if item.DefendRange > 0 {
				p := instance.ToBytes(Position)
				positions := logic.RangeDistance(p, int(item.DefendRange-1))
				logic.OnListen(instance, selfIdentity, &ListenLogic{
					Nodes:  positions,
					Switch: true,
					Events: []byte{ListenSystemEvent},
				}, logic.CurrentTime())
			}
		}
	}
}

func (logic *TypeMap) OnDestroyBefore(from cooperate.PropsInstance, instance cooperate.PropsInstance) {
}

func (logic *TypeMap) OnDestroyAfter(instance cooperate.PropsInstance, current bool) {
	switch instance.GetDataType() {
	case BuildType:
		if current {
			p := instance.ToBytes(Position)
			pp := instance.ToBytesSlice(Positions)
			pp = append(pp, p)
			logic.UpdateFixed(pp, 0, 0, 0, nil, logic.CurrentTime())
		}
	case ItemType:
		if current {
			//p := instance.ToBytes(Position)
			//pp := instance.ToBytesSlice(Positions)
			//pp = append(pp, p)
			//logic.UpdateFixed(pp, 0, 0, 0, nil, logic.CurrentTime())
		}
	}
}
